package battleship;

import java.util.*;

/**
 *
 * @author HUBERT Jean-Philippe <jean-philippe.hubert@uqac.ca>
 * UQAC - Université du Québec à Chicoutimi
 *
 */
class IABattleShip {

    GrilleMemoire connaissanceIA;
    BateauIA[] listeBateaux;
    Regle R1_manque;
    Regle R2_manque_BateauTouche;
    Regle R3_touche;
    Regle R4_touche_coule;
    Regle R5_touche_bateauTouche_coule;
    Regle RX_appliquee;
    boolean ok;
    FenetreJeu parent;
    int nbregleApplicable;
    Queue<int[]> fileCaseAJouer;
    Queue<Integer> fileBateauAChasser;

    public IABattleShip(FenetreJeu parent, Bateau[] listeBateauxParents) {
        initIABattleShip(parent, listeBateauxParents);
    }

    /**
     * Initalisation des membres du moteur d'inférence
     *
     * @param parent référence vers FenetreJeu
     * @param listeBateauxParents Liste des bateaux du jeu
     */
    private void initIABattleShip(FenetreJeu parent, Bateau[] listeBateauxParents) {
        if (parent == null) {
            throw new NullPointerException("-_-");
        }

        this.parent = parent;
        this.ok = false;
        connaissanceIA = new GrilleMemoire(FenetreJeu.LARGEUR_GRILLE, FenetreJeu.LARGEUR_GRILLE);
        connaissanceIA.print();

        if (listeBateauxParents == null) {
            throw new NullPointerException("Liste de Bateaux nulle -_-");
        }

        this.listeBateaux = new BateauIA[parent.listeBateau.length];

        for (int k = 0; k < parent.listeBateau.length; k++) {
            listeBateaux[k] = new BateauIA(parent.listeBateau[k]);
        }

        //ETABLISSEMENT DES REGLES
        this.R1_manque = new Regle(true, false, false, false, 1, this);
        this.R2_manque_BateauTouche = new Regle(true, false, true, false, 3, this);
        this.R3_touche = new Regle(false, true, true, false, 2, this);
        this.R4_touche_coule = new Regle(false, true, false, true, 1, this);
        this.R5_touche_bateauTouche_coule = new Regle(false, true, true, true, 3, this);
        //règle qui sera appliquée
        this.RX_appliquee = null;

        this.nbregleApplicable = 0;

        //file contenant la liste des coups qu'il faut jouer
        this.fileCaseAJouer = new LinkedList<int[]>();
        //file des bateaux à chasser (dont on connait au moins une case)
        this.fileBateauAChasser = new LinkedList<Integer>();
    }

    /**
     * .Methode d'instance qui s'exécute lors du clic sur le bouton JOUER
     */
    public void IA_jouer_un_coup() {
        if (!this.parent.isTerminer()) {
            this.ok = false;
            int[] coord = new int[2];
            
            //Premier coup, on lance un coup aléatoire
            if (this.parent.getNbCoup() == 0) {
                R1_manque.appliquerConsequence();
            }
            
            while (!ok) {
                coord = new int[2];
                coord = this.fileCaseAJouer.poll();
                if (coord == null) {
                    throw new NullPointerException("FileCaseAJouer null");
                }

                ok = this.parent.jouer(coord[0], coord[1]);

                /**
                 * Si les coordonnées du dernier coup sont déjà jouées on relance un coup aléatoire
                 */
                if (!ok && this.fileCaseAJouer.isEmpty())
                {
                    R1_manque.appliquerConsequence();
                }
            }

            //Reinitialisation du compteur de regle applicable
            this.nbregleApplicable = 0;

            // Mise a jour des connaissances de l'IA et de la liste des bateaux
            this.connaissanceIA.setGrilleCases(this.parent.CensureGrille());
            this.connaissanceIA.MAJgrilleNumeroTour();


            for (int k = 0; k < listeBateaux.length; k++) {
                listeBateaux[k].setBateau(parent.listeBateau[k]);
                listeBateaux[k].MAJTourCoule();
                listeBateaux[k].MAJTourPTouche();
            }

            if (!this.fileBateauAChasser.isEmpty() && this.listeBateaux[this.fileBateauAChasser.element()].getEtat() == 0){
                this.fileBateauAChasser.poll();
            }


            // On verifie les regles applicables et on les met a jour
            if (!R1_manque.verifier()) {
                R1_manque.setMarque(true);
            } else {
                R1_manque.setMarque(false);
            }

            if (!R2_manque_BateauTouche.verifier()) {
                R2_manque_BateauTouche.setMarque(true);
            } else {
                R2_manque_BateauTouche.setMarque(false);
            }

            if (!R3_touche.verifier()) {
                R3_touche.setMarque(true);
            } else {
                R3_touche.setMarque(false);
            }

            if (!R4_touche_coule.verifier()) {
                R4_touche_coule.setMarque(true);
            } else {
                R4_touche_coule.setMarque(false);
            }

            if (!R5_touche_bateauTouche_coule.verifier()) {
                R5_touche_bateauTouche_coule.setMarque(true);
            } else {
                R5_touche_bateauTouche_coule.setMarque(false);
            }

            //Choix des regles
            //On compte le nombre de regles applicables
            if (R1_manque.estAplicable()) {
                RX_appliquee = R1_manque;
                nbregleApplicable++;
                System.out.println("R1");
            }
            if (R2_manque_BateauTouche.estAplicable()) {
                RX_appliquee = R2_manque_BateauTouche;
                nbregleApplicable++;
                System.out.println("R2");
            }
            if (R3_touche.estAplicable()) {
                RX_appliquee = R3_touche;
                nbregleApplicable++;
                System.out.println("R3");
            }
            if (R4_touche_coule.estAplicable()) {
                RX_appliquee = R4_touche_coule;
                nbregleApplicable++;
                System.out.println("R4");
            }
            if (R5_touche_bateauTouche_coule.estAplicable()) {
                RX_appliquee = R1_manque;
                nbregleApplicable++;
                System.out.println("R5");
            }


            //On applique la conséquence
            if (nbregleApplicable == 1) {
                this.RX_appliquee.appliquerConsequence();
            }

            //Affichage pour debug...
            //if (this.parent.getNbCoup() >= 0) {

                /*
                 * connaissanceIA.print();
                 * this.R1_manque.testPrecondition();
                 * System.out.println("parent b0 etat="+this.parent.listeBateau[0].getEtat()+" tour coule="+ this.listeBateaux[0].getTourCoule());
                 * System.out.println("parent b1 etat="+this.parent.listeBateau[1].getEtat()+" tour coule="+ this.listeBateaux[1].getTourCoule());
                 * System.out.println("parent b2 etat="+this.parent.listeBateau[2].getEtat()+" tour coule="+ this.listeBateaux[2].getTourCoule());
                 * System.out.println("parent b3 etat="+this.parent.listeBateau[3].getEtat()+" tour coule="+ this.listeBateaux[3].getTourCoule());
                 * System.out.println("parent b4 etat="+this.parent.listeBateau[4].getEtat()+" tour coule="+ this.listeBateaux[4].getTourCoule());
                 */
                //this.R1_manque.testPrecondition();
                /*System.out.println("R1_manque : " + this.R1_manque.verifier());
                System.out.println("R2_manque_BateauTouche : " + this.R2_manque_BateauTouche.verifier());
                System.out.println("R3_touche : " + this.R3_touche.verifier());
                System.out.println("R4_touche_coule : " + this.R4_touche_coule.verifier());
                System.out.println("R5_touche_bateauTouche_coule : " + this.R5_touche_bateauTouche_coule.verifier());*/
                /*System.out.println("Derniere case jouee : x=" + this.connaissanceIA.derniereCase()[0] + " y=" + this.connaissanceIA.derniereCase()[1]);
                if (!this.fileBateauAChasser.isEmpty()) {
                    System.out.println("Bateau Chassé=" + this.fileBateauAChasser.element());
                }
                if (!this.fileCaseAJouer.isEmpty()) {
                    System.out.println("Prochain coup : x=" + this.fileCaseAJouer.element()[0] + " y=" + this.fileCaseAJouer.element()[1]);
                }
                System.out.println("____________________________________________");
            }*/

            this.parent.afficherGillePartielle();
        } else {
            this.parent.getMonLabel().setText("La partie est terminee (" + this.parent.getNbCoup() + " coups)");
        }
    }

    // ****************************************************************
    // Methode qui genere aleatoirement un nombre entre minNum et maxNum
    // ****************************************************************
    protected int getRandomNum(int minNum, int maxNum) {
        int MonChiffre = maxNum + 1;

        while (MonChiffre > maxNum) {
            MonChiffre = (int) (minNum + (Math.random() * (maxNum + 1)));
        }
        return MonChiffre;
    }

    // ***************************************************************
    // Gestion de la file de coups a jouer
    // ***************************************************************
    protected void viderFileCoord() {
        this.fileCaseAJouer.clear();
    }


     /**
     * 
     * this.consequence = 3
     * @param x
     * @param y
     */
    public void joueLigneColonne(int x, int y){
        //Si on touche un bateau pour la première fois, on met ce bateau en tete de liste de chasse
        if (this.fileBateauAChasser.isEmpty()){
            this.fileBateauAChasser.add(this.connaissanceIA.numBateauDerniereCase());
            this.ajouterColonne(x, y);
            this.ajouterLigne(x, y);
        }
        else if(!this.fileBateauAChasser.isEmpty() && this.fileBateauAChasser.element() == this.connaissanceIA.numBateauDerniereCase())
        {
            //rien?
        }
        else {
            this.ajouterColonne(x, y);
            this.ajouterLigne(x, y);
        }
    }

    /**
     * ajoute une ligne de coordonnée x de coups a jouer dans la file
     * @param x
     * @param y
     */
    protected void ajouterLigne(int x, int y) {
        int[] coord;
        int longueurBateauChasse = this.listeBateaux[this.fileBateauAChasser.element()].getLongueur() - 1;

        if (longueurBateauChasse < 2 && longueurBateauChasse > 5) {
            System.out.println("Erreur longueur bateau");
        }

        //x,y+1 -> x,y+longueurBateauChasse-1
        //x,y-longueurBateauChasse-1 -> x,y-1
        while (longueurBateauChasse > 0) {
            if (y - longueurBateauChasse > 0)
            {
                coord = new int[2];
                coord[0] = x;
                coord[1] = y - longueurBateauChasse;
                this.fileCaseAJouer.add(coord);
            }
            if (y + longueurBateauChasse < FenetreJeu.LARGEUR_GRILLE){
                coord = new int[2];
                coord[0] = x;
                coord[1] = y + longueurBateauChasse;
                this.fileCaseAJouer.add(coord);
            }
            longueurBateauChasse--;
        }
    }

    /**
     * Ajoute une colonne de coordonnée y de case a jouer dans la file
     * @param x
     * @param y
     */
    protected void ajouterColonne(int x, int y) {
        int[] coord;
        int longueurBateauChasse = this.listeBateaux[this.fileBateauAChasser.element()].getLongueur() - 1;

        if (longueurBateauChasse < 2 && longueurBateauChasse > 5) {
            System.out.println("Erreur longueur bateau");
        }

        //x-1,y -> x-longueurBateauChasse-1
        //x+1,y -> x+longueurBateauChasse-1

        while (longueurBateauChasse > 0) {
            if (x - longueurBateauChasse > 0) {
                coord = new int[2];
                coord[0] = x - longueurBateauChasse;
                coord[1] = y;
                this.fileCaseAJouer.add(coord);
            }
            if (x + longueurBateauChasse < FenetreJeu.LARGEUR_GRILLE){
                coord = new int[2];
                coord[0] = x + longueurBateauChasse;
                coord[1] = y;
                this.fileCaseAJouer.add(coord);
            }
            longueurBateauChasse--;
        }
    }
}
